import java.util.*;
// 0.3910638825285788 14.625203928598632 62.03885820746539 2.961158254752793 10.829330563065593 0.0027014261816038134 0.016444225322982065 10.23752559063775
public class PlayerSkeleton {
	public static Random r;
	public static int pieceMasks[][];
	public static int masks[];

	public static double[] coe = {38.855296043926764, 56.20205456936216, 124.73715283257751, 2.2640909982938533, 50.258925572849, 22.749869889548403, -58.04938966878111, 72.65467538019358, 70.43549465474388, 266.0913423308626};

	//implement this function to have a working system
	public static int pickMove(State s, int[][] legalMoves) {
		// get data from state
		int[][] board = s.getField();

		int[] top = s.getTop();
		int[][][] pBottom = State.getpBottom();
		int[][][] pTop = State.getpTop();
		int[][] pWidth = State.getpWidth();
		int[][] pHeight = State.getpHeight();
		int nextPiece = s.getNextPiece();
		int best = 0;
		double bh = Double.MAX_VALUE, bt = 999;
		for(int i = 0; i < legalMoves.length; i++){
			// iterate over each possible moves
			int orient = legalMoves[i][0];
			int slot = legalMoves[i][1];
			int pw = pWidth[nextPiece][orient];
			int[] bottoms = pBottom[nextPiece][orient];
			int ph = pHeight[nextPiece][orient];
			int[] tops = pTop[nextPiece][orient];

			// height is the lowest row the current move can reach
			int height = top[slot]-pBottom[nextPiece][orient][0];
			for(int c = 1; c < pw; c++) {
				height = Math.max(height,top[slot+c]-bottoms[c]);
			}
			if(height+ph >= State.ROWS)continue;

			// lines touching the wall
			int touchwall = 0;
			if(slot == 0){
				touchwall += tops[0] - bottoms[0];
			}else if(slot + pw == State.COLS){
				touchwall += tops[pw - 1] - bottoms[pw - 1];
			}

			// temporarily fill the board
			for(int j = 0; j < pw; j++) {
				for(int h = height+bottoms[j]; h < height+tops[j]; h++) {
					board[h][j+slot] = -1;
				}
			}
			int rowsCleared = 0;
			int cleared = 0;
			for(int r = height+ph-1; r >= height; r--) {
				boolean full = true;
				for(int c = 0; c < State.COLS; c++) {
					if(board[r][c] == 0) {
						full = false;
						break;
					}
				}
				if(full) {
					rowsCleared++;
					cleared |= 1<<(height+ph-1 -r);
				}
			}

			int hh = 0, block = 0;
			int maxh = 0;
			int wells = 0, lastheight = 0, llheight = 0;
			int minh = 999, curh = 0;
			int transition = 0;
			int change = 0;
			int colTransition = 0;
			for(int j = 0; j < State.COLS; j++){
				// compute column transition, changes in top, wells
				int r = 0;
				int curhole = 0;
				boolean hasHole = false;
				int t = top[j];
				if(j >= slot && j < (slot + pw)){
					t = height + tops[j - slot];
				}
				curh = t;
				while(r <= t){
					if(board[r][j] == 0){
						if(!hasHole)colTransition++;
						hasHole = true;
						curhole++;
					}else{
						if(board[r][j] == -1 && (cleared & (1<<(height+ph-1 -r))) > 0){
							r++;
							curh--;
							continue;
						}
						if(hasHole){
							hh += curhole;
							block++;
							if(curhole != 0) colTransition++;
							curhole = 0;
						}
					}
					r++;
				}
				if(j > 1){
					if((lastheight < curh) && (lastheight < llheight)){
						wells += Math.min(curh - lastheight, llheight - lastheight);
					}
				}else if(j == 1 && lastheight < curh){
					wells += curh - lastheight;
				}
				if(j > 0){
					if(curh != lastheight){
						change++;
					}
				}
				llheight = lastheight;
				lastheight = curh;
				maxh = Math.max(curh, maxh);
				minh = Math.min(curh, minh);
			}
			for(int r = 0; r < (maxh + rowsCleared) && r < State.ROWS; r++){
				// computes row transition
				if(r >= height && r < (height + ph) && (cleared & (1<<(height+ph-1 -r))) > 0){
					continue;
				}
				for(int c = 0; c + 1 < State.COLS; c++){
					if((board[r][c] == 0 && board[r][c + 1] != 0) || (board[r][c] != 0 && board[r][c + 1] == 0)){
						transition++;
					}
				}
			}
			if(llheight > lastheight) wells += llheight - lastheight;
			
			// lines touching other blocks
			int touch = 0;
			if(height == 0){
				for(int c = 0; c < pw; c++){
					if(bottoms[c] == 0)touch++;
				}
			}else{
				for(int c = 0; c < pw; c++){
					if(board[height - bottoms[c] + 1][slot + c] > 0)touch++;
				}
			}

			for(int j = 0; j < pw; j++) {
				for(int h = height+bottoms[j]; h < height+tops[j]; h++) {
					board[h][j+slot] = 0;
					if(j + slot + 1 < State.COLS && board[h][j + slot + 1] > 0)touch++;
					if(j + slot - 1 >= 0 && board[h][j + slot - 1] > 0)touch++;
				}
			}
			double val = h(height, change, -touch, hh, rowsCleared, block, -touchwall, wells, transition, colTransition);
			if(val < bh){
				best = i;
				bh = val;
			}
		}

		return best;
	}

	private static double h(int height, int changes, int touch, int holes, int rowsCleared, int block, int touchWall, double wells, int trnaistion, int colTransition){
		return  coe[0] * height + coe[2] * holes + coe[3] * touch + coe[4] * touchWall - coe[1] * rowsCleared
			+ coe[5] * block + coe[6] * changes + coe[7] * wells + coe[8] * trnaistion + coe[9] * colTransition;
	}

	
	public static void main(String[] args) {
		int max = 0, min = 9999999;
		int iter = 1000;
		while(iter-->0){
			State s = new State();
			TFrame tf = new TFrame(s);
			PlayerSkeleton p = new PlayerSkeleton();
			r = new Random();
			while(!s.hasLost()) {
				s.makeMove(p.pickMove(s,s.legalMoves()));
				s.draw();
				s.drawNext(0,0);
				// try {
				// 	Thread.sleep(100);
				// } catch (InterruptedException e) {
				// 	e.printStackTrace();
				// }
			}
			tf.dispose();
			System.out.println("You have completed "+s.getRowsCleared()+" rows.");
			max = Math.max(max, s.getRowsCleared());
			min = Math.min(min, s.getRowsCleared());
			System.out.println("Max: " + max + ", Min: " + min);
		}
	}
	
}
